/*!
    \copyright  Copyright (c) 2024 - 2025 Qualcomm Technologies International, Ltd.
                All Rights Reserved.
                Qualcomm Technologies International, Ltd. Confidential and Proprietary.
    \file
    \ingroup    leabm
    \brief      The le broadcast profile audio params
*/

#if defined(INCLUDE_LE_AUDIO_BROADCAST)

#include "le_broadcast_music_param.h"
#include "le_broadcast_manager_source.h"
#include "le_broadcast_manager.h"
#include "le_audio_messages.h"
#include "kymera_adaptation_audio_protected.h"
#include "audio_lea_types.h"
#include "multidevice.h"
#include "pacs_utilities.h"
#include "pacs_audio_locations.h"
#include "kymera.h"
#include "volume_utils.h"

#include <stdlib.h>
#include <logging.h>

static appKymeraLeStreamType leBroadcastMusicSource_GetStreamType(void)
{
    appKymeraLeStreamType stream_type = KYMERA_LE_STREAM_MONO;
    broadcast_source_state_t *broadcast_source = LeBroadcastManager_GetSourceOfActiveBis();
    uint16 right_channel = LeBroadcastManager_SourceGetBisStreamHandle(broadcast_manager_bis_location_right);

    if (Multidevice_IsDeviceStereo())
    {
        if (right_channel != 0)
        {
            stream_type = KYMERA_LE_STREAM_DUAL_MONO;
        }
    }

    if (stream_type == KYMERA_LE_STREAM_MONO && leBroadcastManager_IsStereoBis(broadcast_source,
                                                                               LeBroadcastManagerSource_GetBisIndexToRender(broadcast_source).audio_channel_allocation))
    {
        switch (Multidevice_GetSide())
        {
            default:
            case multidevice_side_both:
                stream_type = KYMERA_LE_STREAM_STEREO_USE_BOTH;
                break;

            case multidevice_side_left:
                stream_type = KYMERA_LE_STREAM_STEREO_USE_LEFT;
                break;

            case multidevice_side_right:
                stream_type = KYMERA_LE_STREAM_STEREO_USE_RIGHT;
                break;
        }
    }

    return stream_type;
}

bool LeBroadcastMusicSource_GetAudioConnectParameters(audio_source_t source, source_defined_params_t * source_params)
{
    DEBUG_LOG_VERBOSE("LeBroadcastMusicSource_GetAudioConnectParameters");
    switch(source)
    {
        case audio_source_le_audio_broadcast:
        {
            le_audio_connect_parameters_t *conn_param = (le_audio_connect_parameters_t*)PanicUnlessMalloc(sizeof(le_audio_connect_parameters_t));
            memset(conn_param, 0, sizeof(le_audio_connect_parameters_t));  

            LeBroadcastManager_GetIsoHandleInfo(&conn_param->media.iso_handle_list);
            conn_param->media.channels_to_render = PacsAudioLocations_GetSinkAudioLocationToRender();
            conn_param->media_present = TRUE;
            conn_param->media.volume = AudioSources_CalculateOutputVolume(audio_source_le_audio_broadcast);
            conn_param->media.sample_rate = LeBroadcastManager_SourceGetAudioStreamSampleRate();
            conn_param->media.frame_length = LeBroadcastManager_SourceGetAudioStreamOctetsPerFrame() * LeBroadcastManager_SourceGetAudioStreamCodecFrameBlocksPerSdu();
            conn_param->media.frame_duration = LeBroadcastManager_SourceGetAudioStreamFrameDuration();
            conn_param->media.start_muted = leBroadcastManager_GetStartMuted();
            conn_param->media.presentation_delay = LeBroadcastManager_SourceGetAudioStreamPresentationDelay();
            conn_param->media.codec_type = KYMERA_LE_AUDIO_CODEC_LC3;/* @TODO Supports only LC3 codec. */
            conn_param->media.codec_id = LeBroadcastManager_GetSourceOfActiveBis()->codec_id;
            conn_param->media.stream_type = leBroadcastMusicSource_GetStreamType();
            conn_param->media.codec_frame_blocks_per_sdu = LeBroadcastManager_SourceGetAudioStreamCodecFrameBlocksPerSdu();
            conn_param->microphone_present = FALSE;
            source_params->data = (void *)conn_param;
            source_params->data_length = sizeof(le_audio_connect_parameters_t);
            DEBUG_LOG("LeBroadcastMusicSource_GetAudioConnectParameters stream type:%d",conn_param->media.stream_type);
        }
        break;
        
        default:
            return FALSE;
    }
    return TRUE;
}

void LeBroadcastMusicSource_FreeAudioConnectParameters(audio_source_t source, source_defined_params_t * source_params)
{
    DEBUG_LOG_VERBOSE("LeBroadcastMusicSource_FreeAudioConnectParameters");
    if (source == audio_source_le_audio_broadcast)
    {
        PanicNull(source_params);
        PanicFalse(source_params->data_length == sizeof(le_audio_connect_parameters_t));

        if(source_params->data)
        {
            free(source_params->data);
            memset(source_params, 0, sizeof(*source_params));
        }
    }
}

bool LeBroadcastMusicSource_GetAudioDisconnectParameters(audio_source_t source, source_defined_params_t * source_params)
{
    DEBUG_LOG_VERBOSE("LeBroadcastMusicSource_GetAudioDisconnectParameters");
    UNUSED(source);
    PanicNull(source_params);

    memset(source_params, 0, sizeof(*source_params));
    return TRUE;
}

void LeBroadcastMusicSource_FreeAudioDisconnectParameters(audio_source_t source, source_defined_params_t * source_params)
{
    DEBUG_LOG_VERBOSE("LeBroadcastMusicSource_FreeAudioDisconnectParameters");
    UNUSED(source);
    PanicNull(source_params);

    if(source_params->data)
    {
        free(source_params->data);
        memset(source_params, 0, sizeof(*source_params));
    }
}

bool LeBroadcastManager_UpdateSinkAudioLocationToRender(uint32 audio_loc)
{
    source_defined_params_t params_to_update;
    uint32 pacs_locations = PacsAudioLocations_GetPacAudioLocation(TRUE);
    uint32 sink_loc = PacsAudioLocations_GetSinkAudioLocationToRender();

    DEBUG_LOG("LeBroadcastManager_UpdateSinkAudioLocationToRender updated_location:0x%x pacs locations:%d",
               audio_loc, pacs_locations);

    /*Check for valid audio location and also if this is already covered within PACS.*/
    if ((audio_loc == (audio_loc & pacs_locations)) && PacsAudioLocations_IsAudioLocationValid(audio_loc))
    {
        /*Verify if the entered audio location is currently being rendered. If it matches, take no action.*/
        if (sink_loc != audio_loc)
        {
            PacsAudioLocations_SetSinkAudioLocationToRender(audio_loc);
            if(LeBroadcastMusicSource_GetAudioConnectParameters(audio_source_le_audio_broadcast, &params_to_update))
            {
                le_audio_connect_parameters_t * updated_connect_params = (le_audio_connect_parameters_t *)params_to_update.data;
                updated_connect_params->reconfig = TRUE;
                int16 volume_in_db = VolumeUtils_GetVolumeInDb(updated_connect_params->media.volume);
                Kymera_LeAudioStart(updated_connect_params->media_present,updated_connect_params->microphone_present,updated_connect_params->reconfig,
                                     volume_in_db,&updated_connect_params->media,&updated_connect_params->microphone);
                LeBroadcastMusicSource_FreeAudioConnectParameters(audio_source_le_audio_broadcast, &params_to_update);
                return TRUE;
            }
        }
        else
        {
            DEBUG_LOG("LeBroadcastManager_UpdateSinkAudioLocationToRender: The entered audio location is same as audio locations currenly rendering");
        }
    }
    else
    {
        DEBUG_LOG("LeBroadcastManager_UpdateSinkAudioLocationToRender: The entered audio location does not exists in PACS record");
    }
    return FALSE;
}

#endif /* INCLUDE_LE_AUDIO_BROADCAST */
